<template>
  <div class="component component-json">
    <div class="container-center">
      <div class="over-hidden">
        <router-link
          class="btn btn-default pull-right icon icon-arrowsleftline mt-lg"
          :to="getMicroRoute('/tools')"
        >
          返回列表</router-link>
        <h2 class="text-left">JSON格式化</h2>
      </div>
      <div class="row">
        <div class="col-xs-6 row-cell">
          <div class="form-group">
            <label class="form-label">输入文本：</label>
            <div class="form-field">
              <textarea id="RawJson" class="form-textarea json-input" rows="4" v-model="inputData"></textarea>
            </div>
          </div>
        </div>
        <div class="col-xs-6 row-cell">
          <div class="form-group">
            <label class="form-label">输出文本：</label>
            <div class="form-field">
              <textarea class="form-textarea json-input" rows="4" v-model="outputData"></textarea>
            </div>
          </div>
        </div>
        <div class="row-cell clear clear-after pt-sm mb-sm">
          <div class="pull-left">
            <a class="btn btn-theme mr-md" @click="toJSON">字符串转JSON对象</a>
            <a class="btn btn-primary mr-md" @click="toStringify">JSON对象转字符串</a>
            <a class="btn btn-theme mr-md" @click="toParseRows">行字符转JSON对象</a>
            <a class="btn btn-theme mr-md" @click="toParseCookie">Cookie转JSON对象</a>
            <a class="btn btn-theme" @click="handleExportCSV">导出CSV</a>
          </div>
          <div class="pull-right">
            <span class="form-inline">
              <SwitchRich v-model="isDeep" label="深度格式" />
            </span>
            <span class="form-inline">
              <SwitchRich v-model="isPure" label="去除引号" />
            </span>
            <span class="form-inline">
              <SwitchRich v-model="isPipe" label="覆盖输入" />
            </span>
            <Pipe name="json" :operation="{inputData: outputData}"/>
          </div>
        </div>
        <div class="col-xs-12 row-cell text-json-view">
          <h4>格式文本：</h4>
          <div id="Canvas" class="Canvas">
            <pre class="CodeContainer"><span class="String"></span></pre>
          </div>
          <div class="setting form-inline">
            <div class="form-group">
              <label class="form-label">主题：</label>
              <select class="form-select" v-model="theme">
                <option value="">默认</option>
                <option value="one-dark">one-dark</option>
                <option value="vs-code">vs-code</option>
              </select>
            </div>
            <div class="form-group">
              <label class="form-label">折叠全部：</label>
              <select class="form-select" v-model="closed">
                <option :value="false">false</option>
                <option :value="true">true</option>
              </select>
            </div>
            <div class="form-group">
              <label class="form-label">层级：</label>
              <select class="form-select" v-model="deep">
                <option v-for="item in 99" :value="item" :key="item">{{item}}</option>
              </select>
            </div>
            <div class="form-group">
              <label class="form-label">图标风格：</label>
              <select class="form-select" v-model="iconStyle">
                <option value="square">square</option>
                <option value="circle">circle</option>
                <option value="triangle">triangle</option>
              </select>
            </div>
            <div class="form-group">
              <label class="form-label">图标颜色：</label>
              <input class="form-input wide-xs" type="color" v-model="color1">
              <input class="form-input wide-xs" type="color"  v-model="color2">
            </div>
            <div class="form-group">
              <label class="form-label">字体大小：</label>
              <select class="form-select" v-model="fontSize">
                <option v-for="item in 10" :value="item+11" :key="item">{{item+11}}</option>
              </select>
            </div>
            <div class="form-group">
              <label class="form-label">行高：</label>
              <select class="form-select" v-model="lineHeight">
                <option v-for="item in 20" :value="item*2+14" :key="item">{{item*2+14}}</option>
              </select>
            </div>
          </div>
          <div class="content">
            <JsonView
              :data="dataJSON" :theme="theme" :deep="deep"
              :iconStyle="iconStyle" :fontSize="fontSize"
              :lineHeight="lineHeight" :closed="closed"
              :iconColor="iconColor"
            />
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import SwitchRich from '@/components/vue/components/switch-rich/2.0/switch-rich.vue'
import messager from '../../../components/messager/messager.js'
import { objecter, parser } from '@daelui/dogjs/dist/components'
import Pipe from '../index/pipe.vue'
import JsonView from 'vue-json-views'

/* JSON转换 */
export default {
  components: {
    SwitchRich,
    Pipe,
    JsonView
  },

  data () {
    return {
      inputData: '{\n\n}',
      outputData: '{\n\n}',
      dataJSON: {},
      isPipe: false,
      isDeep: false, // 深度格式
      isPure: false, // 去除引号
      tabSize: 2, // 缩进量
      theme: '',
      fontSize: 14,
      lineHeight: 24,
      deep: 3,
      closed: false,
      iconStyle: 'square',
      iconColor: ['#7C878E', '#A2AAAD', '#C1C6C8'],
      color1: '',
      color2: ''
    }
  },

  methods: {
    /**
     * @function 获取字符串解析后的对象
     * @return {Object}
    */
    getObject () {
      let data = null
      data = this.toObject(this.inputData)
      if (data === null) {
        messager.warning('数据非JSON格式，格式化失败')
        return
      }
      // 子级解析
      if (this.isDeep) {
        this.solveObject(data)
      }

      return data
    },

    // 转化为对象
    toObject (input) {
      let data = null
      // JSON解析
      try {
        data = JSON.parse(input)
      } catch (e) {
        data = null
      }
      // 函数解析
      if (data === null) {
        try {
          data = (new Function('return ' + input))()
        } catch (e) {
          data = null
        }
      }
      // 转义解析
      if (data === null) {
        try {
          data = JSON.parse('{"a":"' + input + '"}')
          data = JSON.parse(data.a)
        } catch (e) {
          data = null
        }
      }

      return data
    },

    /**
     * @function 解析子级对象
    */
    solveObject (data) {
      // 数组形式
      if (Array.isArray(data)) {
        data.forEach(item => {
          this.solveObject(item)
        })
      }
      // 对象形式
      else if (isObject(data)) {
        for (let key in data) {
          // JSON格式字符
          if (typeof data[key] === 'string' && /^\s*({|\[)/.test(data[key])) {
            try {
              data[key] = this.toObject(data[key])
            } catch (e) {}
          }
          // 对象形式
          if (isObject(data[key])) {
            this.solveObject(data[key])
          }
        }
      }

      function isObject (data) {
        return Object.prototype.toString.call(data) === '[object Object]' || Array.isArray(data)
      }
    },

    /**
     * @function 转化为JSON对象
    */
    toJSON () {
      // 转换为对象
      let data = this.getObject()
      if (!data) {
        return false
      }
      this.dataJSON = data
      this.outputData = JSON.stringify(data, null, this.tabSize)
      // 去除引号
      if (this.isPure) {
        this.outputData = this.pureQuota(this.outputData)
      }
      // 是否管道操作
      if (this.isPipe === true) {
        this.inputData = this.outputData
      }
    },

    /**
     * @function 转化为JSON字符
    */
    toStringify () {
      // 转换为对象
      let data = this.getObject()
      if (!data) {
        return false
      }
      this.outputData = JSON.stringify(data, null, 0)
      // 去除引号
      if (this.isPure) {
        this.outputData = this.pureQuota(this.outputData)
      }
      // 是否管道操作
      if (this.isPipe === true) {
        this.inputData = this.outputData
      }
    },

    /**
     * @function 去除引号
    */
    pureQuota (str) {
      if (typeof str === 'string') {
        str = str.replace(/\"([^\"]+)?\":/g, function (a, b) {
          if (/^\d/.test(b) || !/\w+/i.test(b)) {
            return `"${b}":`
          }
          return `${b}:`
        })
        str = str.replace(/(:\s*)\"([^\"]*)\"/g, function (a, b, c) {
          return `${b}'${c}'`
        })
      }
      return str
    },

    /**
     * @function 解析行字符
    */
    toParseRows () {
      this.outputData = parser.parseEuqalSeparate(this.inputData, ':', '\n')
      if (objecter.isObject(this.outputData)) {
        // 子级解析
        if (this.isDeep) {
          this.solveObject(this.outputData)
        }
        this.dataJSON = this.outputData
        this.outputData = JSON.stringify(this.outputData, null, this.tabSize)
      }
      // 是否管道操作
      if (this.isPipe === true) {
        this.inputData = this.outputData
      }
    },

    /**
     * @function 解析Cookie
    */
    toParseCookie () {
      this.outputData = parser.parseEuqalSeparate(this.inputData, '=', ';')
      if (objecter.isObject(this.outputData)) {
        // 子级解析
        if (this.isDeep) {
          this.solveObject(this.outputData)
        }
        this.dataJSON = this.outputData
        this.outputData = JSON.stringify(this.outputData, null, this.tabSize)
      }
      // 是否管道操作
      if (this.isPipe === true) {
        this.inputData = this.outputData
      }
    },

    handleExportCSV () {
      this.exportCSV(this.outputData)
    },

    // 导出CSV
    exportCSV (jsonData, fileName) {
      jsonData = parser.toObject(jsonData)
      if(!jsonData || typeof jsonData !== 'object') {
        messager.warning('数据不是数组或数据为空')
        return
      }
      if (!Array.isArray(jsonData)) {
        jsonData = [jsonData]
      }
      if (!fileName) {
        fileName = 'exportCSV.csv'
      }
      let one = jsonData[0]
      let csvText = ''
      for (let key in one) {
        csvText += key + ','
      }
      csvText = trim(csvText, ',') + '\n'
      // 增加\t为了不让表格显示科学计数法或者其他格式
      for (let i = 0; i < jsonData.length; i++) {
        let row = ''
        for (let item in jsonData[i]) {
          row += `${jsonData[i][item] + '\t'},`
        }
        csvText += trim(row, ",") + '\n'
      }
      // encodeURIComponent解决中文乱码
      let uri = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(csvText)
      // 通过创建a标签实现
      let link = document.createElement('a')
      link.href = uri
      // 对下载的文件命名
      link.download =  fileName
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)

      // js实现类似php trim函数
      function trim (str, char) {
        if (char) {
          str = str.replace(new RegExp('^\\'+char+'+|\\'+char+'+$', 'g'), '')
        }
        return str.replace(/^\s+|\s+$/g, '')
      }
    }
  },

  mounted () {
    // 管道数据
    if (this.$store.state.inputData) {
      this.inputData = this.$store.state.inputData
      this.$store.state.inputData = ''
    }
  }
}
</script>

<style lang="less">
.json-input{
  height: 450px;
}
.text-pointer{
  cursor: pointer;
  color: #1abd9e;
  font-weight: bolder;
}
.component-json{
  .wide-xs{
    width: 65px;
  }
}
.text-json-view {
  a {
    display: block;
    background-color: #f8f8f9;
    border-radius: 4px;
    padding: 8px 16px;
    border: 1px solid #edeff0;
    border-radius: 4px;
    margin-bottom: 20px;
    text-decoration: none;
    color: #2d8cf0;
  }
  .setting {
    border: 1px solid #ccc;
    padding: 10px 20px;
    border-radius: 4px;
    h3 {
      line-height: 1.6;
      font-size: 18px;
      color: #333;
    }
  }
  .content {
    border: 1px solid #ccc;
    border-top: none;
  }
}
</style>
